﻿using Newtonsoft.Json.Linq;
using ProductCatalog.WebApi.DataLayer;
using ProductCatalog.WebApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace ProductCatalog.WebApi.Controllers
{
    public class ProductController : ApiController
    {
        const int maxPageSize = 30;

        private ProductRepository repository = null;
        public ProductController()
        {
            repository = new ProductRepository();
        }

        //// DELETE api/product
        //[HttpDelete]
        //[ActionName("delete")]
        //public HttpResponseMessage DeleteProductsAndReviews()
        //{
        //    repository.DeleteProductsAndReviews();
        //    var responseMsg = Request.CreateResponse(HttpStatusCode.OK);
        //    return responseMsg;
        //}

        // POST api/product
        //[HttpPost]
        //[ActionName("default")]
        //public HttpResponseMessage AddProductDetails([FromBody]JObject value)
        //{
        //    HttpResponseMessage responseMsg;

        //    try
        //    {
        //        if (value == null)
        //        {
        //            responseMsg = Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Missing or invalid JSON submitted.");
        //        }
        //        else
        //        {
        //            var prodId = repository.AddProductDetails(value);
        //            responseMsg = Request.CreateResponse(HttpStatusCode.Created);
        //            responseMsg.Headers.Location = new Uri(
        //                Request.RequestUri + "/" + (prodId).ToString());
        //        }
        //    }
        //    catch (MissingFieldException ex)
        //    {
        //        responseMsg = Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex.Message);
        //    }

        //    return responseMsg;
        //}

        // GET api/product/{prodId}
        [HttpGet]
        [ActionName("default")]
        public HttpResponseMessage GetProduct(string prodId)
        {
            var product = repository.GetProduct(prodId);
            if (product != null)
                return Request.CreateResponse<Product>(HttpStatusCode.OK, product);
            else
                return Request.CreateErrorResponse(
                    HttpStatusCode.NotFound,
                    string.Format("Product Id {0} not found.", prodId));
        }

        // GET api/product/{prodId}/details
        [HttpGet]
        [ActionName("details")]
        public HttpResponseMessage GetProductDetails(string prodId)
        {
            var productDetails = repository.GetProductDetails(prodId);

            if (productDetails != null)
                return Request.CreateResponse<JObject>(
                    HttpStatusCode.OK, productDetails);
            else
                return Request.CreateErrorResponse(
                    HttpStatusCode.NotFound,
                    string.Format("Product Id {0} not found.", prodId));
        }

        // POST api/product/{prodId}/reviews
        [HttpPost]
        [ActionName("reviews")]
        public HttpResponseMessage AddProductReview(string prodId, [FromBody]Review review)
        {
            if (repository.GetProduct(prodId) != null)
            {
                var reviewId = repository.AddProductReview(prodId, review);
                var responseMsg = Request.CreateResponse(HttpStatusCode.Created);
                responseMsg.Headers.Location = new Uri(
                    Request.RequestUri + "/" + (reviewId).ToString());
                return responseMsg;
            }
            else
                return Request.CreateErrorResponse(
                    HttpStatusCode.NotFound,
                    string.Format("Product Id {0} not found.", prodId));
        }

        // GET api/product/{prodId}/reviews
        [HttpGet]
        [ActionName("reviews")]
        public HttpResponseMessage GetProductReviews(string prodId, [FromUri]int pageIndex = 0, [FromUri]int pageSize = 10)
        {
            // moved paging into mongo
            var reviewsResult = repository.GetProductReviews(prodId, pageIndex * pageSize, pageSize);

            if (reviewsResult != null)
                return Request.CreateResponse<Reviews>(
                    HttpStatusCode.OK, reviewsResult);
            else
                return Request.CreateErrorResponse(
                    HttpStatusCode.NotFound,
                    string.Format("Product Id {0} not found.", prodId));
        }

        // GET api/product/{prodId}/reviews/{reviewId}
        [HttpGet]
        [ActionName("reviews")]
        public HttpResponseMessage GetProductReview(string prodId, string reviewid)
        {
            var review = repository.GetProductReview(prodId, reviewid);
            if (review != null)
                return Request.CreateResponse<Review>(
                       HttpStatusCode.OK, review);
            else
                return Request.CreateErrorResponse(
                    HttpStatusCode.NotFound,
                    string.Format(
                    "No matching record found for Product Id {0} and Review Id {1}.",
                    prodId, reviewid));
        }

        // PUT api/product/{prodId}/reviews/{reviewId}
        [HttpPut]
        [ActionName("reviews")]
        public HttpResponseMessage UpdateProductReview(string prodId, string reviewId, [FromBody]Review review)
        {
            // populate "Review" instance with prodId and ReviewId from URL.
            review.prodId = prodId;
            review.reviewId = reviewId;

            // Update the review.
            if (repository.UpdateProductReview(review))
            {
                var responseMsg = Request.CreateResponse(HttpStatusCode.Created);
                responseMsg.Headers.Location = Request.RequestUri;
                return responseMsg;
            }
            else
            {
                return Request.CreateErrorResponse(
                   HttpStatusCode.NotFound,
                   string.Format(
                   "No matching record found for Product Id {0} and Review ID {1}.",
                   prodId, reviewId));
            }
        }

        // GET api/product/search/prodid?key=1000&key=1001
        [HttpGet]
        [ActionName("searchprodid")]
        public HttpResponseMessage GetProductListByIds([FromUri] string[] key)
        {
            // moved paging into mongo
            var productsResult = repository.GetProductListByIds(key);

            if (productsResult != null)
            {
                var srchResult = new ProductSearchByIdsResult() 
                { Products = productsResult.Products.ToList() };
                return Request.CreateResponse<ProductSearchByIdsResult>(
                    HttpStatusCode.OK, srchResult);
            }
            else
                return Request.CreateErrorResponse(
                    HttpStatusCode.NotFound,
                    string.Format("One of the provided product Ids was not valid: {0}", string.Join(", ", key)));
        }

        //GET /api/product/search/tag?key=book&pageIndex=0&pageSize=10
        [HttpGet]
        [ActionName("searchtag")]
        public HttpResponseMessage GetProductListByTag(string key, int pageIndex = 0, int pageSize = 10)
        {
            // moved paging into mongo
            var productsResult = repository.GetProductListByTag(key);
            productsResult.Products = productsResult.Products.Skip(pageIndex * pageSize).Take(pageSize);

            if (productsResult != null)
                return Request.CreateResponse<ProductSearchResult>(
                    HttpStatusCode.OK, productsResult);
            else
                return Request.CreateErrorResponse(
                    HttpStatusCode.BadRequest,
                    string.Format("The provided tag was not valid: {0}.", key));
        }

        //GET /api/product/search/name?key=sql&pageIndex=0&pageSize=10
        [HttpGet]
        [ActionName("searchname")]
        public HttpResponseMessage GetProductListByName(string key, int pageIndex = 0, int pageSize = 10)
        {
            if (pageSize <= maxPageSize)
            {
                var prodSrchResult = repository.GetProductListByName(key);
                prodSrchResult.Products = prodSrchResult.Products.Skip(pageIndex * pageSize).Take(pageSize);
                return Request.CreateResponse<ProductSearchResult>(HttpStatusCode.OK, prodSrchResult);
            }
            else
                return Request.CreateErrorResponse(
                    HttpStatusCode.BadRequest,
                    string.Format(
                    "pageSize of {0} is too large.  Max pageSize supported is {1}.", pageSize, maxPageSize));
        }

        // GET api/product/tags
        [HttpGet]
        [ActionName("tags")]
        public HttpResponseMessage GetTags()
        {
            var tags = repository.GetAvailableTags();
            return Request.CreateResponse<IEnumerable<string>>(HttpStatusCode.OK, tags);
        }
    }
}
